/*     */ package com.zimbra.cs.gal;
/*     */ 
/*     */ import com.zimbra.common.service.ServiceException;
/*     */ import com.zimbra.common.soap.Element;
/*     */ import com.zimbra.common.util.StringUtil;
/*     */ import com.zimbra.cs.account.EntrySearchFilter;
/*     */ import com.zimbra.cs.account.EntrySearchFilter.AndOr;
/*     */ import com.zimbra.cs.account.EntrySearchFilter.Multi;
/*     */ import com.zimbra.cs.account.EntrySearchFilter.Operator;
/*     */ import com.zimbra.cs.account.EntrySearchFilter.Single;
/*     */ import com.zimbra.cs.account.EntrySearchFilter.Term;
/*     */ import com.zimbra.cs.account.EntrySearchFilter.Visitor;
/*     */ import com.zimbra.cs.account.GalContact;
/*     */ import com.zimbra.cs.mailbox.Contact;
/*     */ import java.util.Iterator;
/*     */ import java.util.List;
/*     */ import java.util.Map;
/*     */ import java.util.Set;
/*     */ import java.util.Stack;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public class GalExtraSearchFilter
/*     */ {
/*     */   public static EntrySearchFilter parseSearchFilter(Element request)
/*     */     throws ServiceException
/*     */   {
/*  41 */     Element filterElem = request.getOptionalElement("searchFilter");
/*  42 */     if (filterElem == null) {
/*  43 */       return null;
/*     */     }
/*     */     
/*  46 */     Element termElem = filterElem.getOptionalElement("conds");
/*  47 */     if (termElem == null)
/*  48 */       termElem = filterElem.getElement("cond");
/*  49 */     EntrySearchFilter.Term term = parseFilterTermElem(termElem);
/*  50 */     EntrySearchFilter filter = new EntrySearchFilter(term);
/*     */     
/*  52 */     return filter;
/*     */   }
/*     */   
/*     */   private static EntrySearchFilter.Term parseFilterTermElem(Element termElem)
/*     */     throws ServiceException
/*     */   {
/*  58 */     String elemName = termElem.getName();
/*  59 */     boolean negation = termElem.getAttributeBool("not", false);
/*  60 */     EntrySearchFilter.Term term; if (elemName.equals("conds")) {
/*  61 */       boolean or = termElem.getAttributeBool("or", false);
/*  62 */       EntrySearchFilter.Multi multiTerm = new EntrySearchFilter.Multi(negation, or ? EntrySearchFilter.AndOr.or : EntrySearchFilter.AndOr.and);
/*  63 */       Iterator<Element> iter = termElem.elementIterator();
/*  64 */       while (iter.hasNext()) {
/*  65 */         EntrySearchFilter.Term child = parseFilterTermElem((Element)iter.next());
/*  66 */         multiTerm.add(child);
/*     */       }
/*  68 */       term = multiTerm; } else { EntrySearchFilter.Term term;
/*  69 */       if (elemName.equals("cond")) {
/*  70 */         String attr = termElem.getAttribute("attr");
/*  71 */         if (attr == null)
/*  72 */           throw ServiceException.INVALID_REQUEST("Missing search term attr", null);
/*  73 */         String op = termElem.getAttribute("op");
/*  74 */         if (op == null)
/*  75 */           throw ServiceException.INVALID_REQUEST("Missing search term op", null);
/*  76 */         String value = termElem.getAttribute("value");
/*  77 */         if (value == null)
/*  78 */           throw ServiceException.INVALID_REQUEST("Missing search term value", null);
/*  79 */         term = new EntrySearchFilter.Single(negation, attr, op, value);
/*     */       } else {
/*  81 */         throw ServiceException.INVALID_REQUEST("Unknown element <" + elemName + "> in search filter", null);
/*     */       }
/*     */     }
/*     */     EntrySearchFilter.Term term;
/*  85 */     return term;
/*     */   }
/*     */   
/*     */   public static abstract class GalExtraQueryCallback implements GalSearchQueryCallback {
/*     */     protected EntrySearchFilter filter;
/*     */     
/*     */     protected GalExtraQueryCallback(EntrySearchFilter filter) {
/*  92 */       this.filter = filter;
/*     */     }
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */     public String getMailboxSearchQuery()
/*     */     {
/* 100 */       GalExtraSearchFilter.MailboxQueryVisitor visitor = new GalExtraSearchFilter.MailboxQueryVisitor();
/* 101 */       this.filter.traverse(visitor);
/* 102 */       String query = visitor.getFilter();
/* 103 */       return StringUtil.isNullOrEmpty(query) ? null : query;
/*     */     }
/*     */     
/*     */     public abstract String getZimbraLdapSearchQuery();
/*     */   }
/*     */   
/*     */   private static class MailboxQueryVisitor implements EntrySearchFilter.Visitor
/*     */   {
/*     */     private final Stack<EntrySearchFilter.Multi> parentTerms;
/*     */     private final StringBuilder query;
/*     */     
/*     */     public MailboxQueryVisitor() {
/* 115 */       this.parentTerms = new Stack();
/* 116 */       this.query = new StringBuilder();
/*     */     }
/*     */     
/*     */     public String getFilter() {
/* 120 */       return this.query.toString();
/*     */     }
/*     */     
/*     */     public void visitSingle(EntrySearchFilter.Single term)
/*     */     {
/* 125 */       EntrySearchFilter.Multi parent = (EntrySearchFilter.Multi)this.parentTerms.peek();
/* 126 */       if ((parent != null) && (parent.getTerms().size() > 1))
/*     */       {
/* 128 */         if (!((EntrySearchFilter.Term)parent.getTerms().get(0)).equals(term)) {
/* 129 */           if (parent.isAnd()) {
/* 130 */             this.query.append(" AND ");
/*     */           } else {
/* 132 */             this.query.append(" OR ");
/*     */           }
/*     */         }
/*     */       }
/* 136 */       EntrySearchFilter.Operator op = term.getOperator();
/* 137 */       boolean negation = term.isNegation();
/*     */       
/* 139 */       if (negation) { this.query.append("-");
/*     */       }
/* 141 */       String attr = term.getLhs();
/*     */       
/*     */ 
/* 144 */       if ("description".equals(attr)) {
/* 145 */         attr = "notes";
/*     */       }
/* 147 */       String val = term.getRhs();
/* 148 */       if (op.equals(EntrySearchFilter.Operator.has)) {
/* 149 */         this.query.append('#').append(attr).append(":(*").append(val).append("*)");
/* 150 */       } else if (op.equals(EntrySearchFilter.Operator.eq)) {
/* 151 */         this.query.append('#').append(attr).append(":(").append(val).append(")");
/* 152 */       } else if (op.equals(EntrySearchFilter.Operator.ge)) {
/* 153 */         this.query.append('#').append(attr).append(":>=").append(val);
/* 154 */       } else if (op.equals(EntrySearchFilter.Operator.le)) {
/* 155 */         this.query.append('#').append(attr).append(":<=").append(val);
/* 156 */       } else if (op.equals(EntrySearchFilter.Operator.gt)) {
/* 157 */         this.query.append('#').append(attr).append(":>").append(val);
/* 158 */       } else if (op.equals(EntrySearchFilter.Operator.lt)) {
/* 159 */         this.query.append('#').append(attr).append(":<").append(val);
/* 160 */       } else if (op.equals(EntrySearchFilter.Operator.startswith)) {
/* 161 */         this.query.append('#').append(attr).append(":(").append(val).append("*)");
/* 162 */       } else if (op.equals(EntrySearchFilter.Operator.endswith)) {
/* 163 */         this.query.append('#').append(attr).append(":(*").append(val);
/*     */       }
/*     */       else {
/* 166 */         this.query.append('#').append(attr).append(":(").append(val).append(")");
/*     */       }
/*     */     }
/*     */     
/*     */     public void enterMulti(EntrySearchFilter.Multi term)
/*     */     {
/* 172 */       this.parentTerms.push(term);
/* 173 */       if (term.isNegation()) {
/* 174 */         this.query.append("-");
/*     */       }
/* 176 */       this.query.append("(");
/*     */     }
/*     */     
/*     */     public void leaveMulti(EntrySearchFilter.Multi term)
/*     */     {
/* 181 */       this.query.append(')');
/* 182 */       this.parentTerms.remove(term);
/*     */     }
/*     */   }
/*     */   
/*     */   public static abstract class FilteredGalSearchResultCallback extends GalSearchResultCallback.PassThruGalSearchResultCallback {
/*     */     private final Set<String> mAttrs;
/*     */     private final EntrySearchFilter mFilter;
/*     */     
/*     */     public FilteredGalSearchResultCallback(GalSearchParams params, EntrySearchFilter filter, Set<String> attrs) {
/* 191 */       super();
/* 192 */       this.mAttrs = attrs;
/* 193 */       this.mFilter = filter;
/*     */     }
/*     */     
/*     */     protected Set<String> neededAttrs() {
/* 197 */       return this.mAttrs;
/*     */     }
/*     */     
/*     */ 
/*     */ 
/*     */     protected boolean matched(Contact c)
/*     */     {
/* 204 */       GalExtraSearchFilter.FilterVisitor visitor = new GalExtraSearchFilter.FilterVisitor(c, null);
/* 205 */       return evaluate(visitor);
/*     */     }
/*     */     
/*     */     protected boolean matched(GalContact c) {
/* 209 */       GalExtraSearchFilter.FilterVisitor visitor = new GalExtraSearchFilter.FilterVisitor(c, null);
/* 210 */       return evaluate(visitor);
/*     */     }
/*     */     
/*     */     private boolean evaluate(GalExtraSearchFilter.FilterVisitor visitor) {
/* 214 */       if (this.mFilter == null) {
/* 215 */         return true;
/*     */       }
/* 217 */       this.mFilter.traverse(visitor);
/* 218 */       return visitor.getResult();
/*     */     }
/*     */   }
/*     */   
/*     */   private static class FilterVisitor implements EntrySearchFilter.Visitor {
/*     */     KeyValue mContact;
/*     */     Stack<Result> mParentResult;
/*     */     
/*     */     private static abstract interface KeyValue {
/*     */       public abstract Object get(String paramString);
/*     */     }
/*     */     
/*     */     private static class ContactKV implements GalExtraSearchFilter.FilterVisitor.KeyValue {
/*     */       Contact mContact;
/*     */       
/*     */       private ContactKV(Contact contact) {
/* 234 */         this.mContact = contact;
/*     */       }
/*     */       
/*     */       public Object get(String key)
/*     */       {
/* 239 */         return this.mContact.get(key);
/*     */       }
/*     */     }
/*     */     
/*     */     private static class GalContactKV implements GalExtraSearchFilter.FilterVisitor.KeyValue
/*     */     {
/*     */       GalContact mGalContact;
/*     */       
/*     */       private GalContactKV(GalContact galContact) {
/* 248 */         this.mGalContact = galContact;
/*     */       }
/*     */       
/*     */       public Object get(String key)
/*     */       {
/* 253 */         return this.mGalContact.getAttrs().get(key);
/*     */       }
/*     */     }
/*     */     
/*     */     private static class Result {
/*     */       EntrySearchFilter.Multi mTerm;
/*     */       Boolean mCurResult;
/*     */       
/*     */       private Result(EntrySearchFilter.Multi term) {
/* 262 */         this.mTerm = term;
/*     */       }
/*     */       
/*     */       private Result(boolean result) {
/* 266 */         setResult(result);
/*     */       }
/*     */       
/*     */       EntrySearchFilter.Multi getTerm() {
/* 270 */         return this.mTerm;
/*     */       }
/*     */       
/* 273 */       private Boolean getResult() { return this.mCurResult; }
/*     */       
/*     */       private void setResult(boolean result)
/*     */       {
/* 277 */         this.mCurResult = Boolean.valueOf(result);
/*     */       }
/*     */       
/*     */       private void negateResult() {
/* 281 */         if (this.mCurResult != null) {
/* 282 */           this.mCurResult = Boolean.valueOf(!this.mCurResult.booleanValue());
/*     */         }
/*     */       }
/*     */     }
/*     */     
/*     */ 
/*     */ 
/*     */     private FilterVisitor(Contact contact)
/*     */     {
/* 291 */       this.mContact = new ContactKV(contact, null);
/* 292 */       this.mParentResult = new Stack();
/*     */     }
/*     */     
/*     */     private FilterVisitor(GalContact galContact) {
/* 296 */       this.mContact = new GalContactKV(galContact, null);
/* 297 */       this.mParentResult = new Stack();
/*     */     }
/*     */     
/*     */     public boolean getResult()
/*     */     {
/* 302 */       return ((Result)this.mParentResult.pop()).getResult().booleanValue();
/*     */     }
/*     */     
/*     */     public void enterMulti(EntrySearchFilter.Multi term) {
/* 306 */       this.mParentResult.push(new Result(term, null));
/*     */     }
/*     */     
/*     */ 
/*     */     public void leaveMulti(EntrySearchFilter.Multi term)
/*     */     {
/* 312 */       Result thisTerm = (Result)this.mParentResult.pop();
/* 313 */       if (thisTerm.getTerm().isNegation()) {
/* 314 */         thisTerm.negateResult();
/*     */       }
/*     */       
/*     */ 
/* 318 */       if (!this.mParentResult.empty())
/*     */       {
/* 320 */         Result parent = (Result)this.mParentResult.peek();
/* 321 */         Boolean parentResult = parent.getResult();
/* 322 */         if ((parentResult == null) || ((parentResult == Boolean.TRUE) && (parent.getTerm().isAnd())) || ((parentResult == Boolean.FALSE) && (!parent.getTerm().isAnd())))
/*     */         {
/*     */ 
/* 325 */           parent.setResult(Result.access$400(thisTerm).booleanValue());
/*     */         }
/*     */       }
/*     */       else {
/* 329 */         this.mParentResult.push(thisTerm);
/*     */       }
/*     */     }
/*     */     
/*     */     public void visitSingle(EntrySearchFilter.Single term)
/*     */     {
/* 335 */       if (!this.mParentResult.empty())
/*     */       {
/* 337 */         Result parent = (Result)this.mParentResult.peek();
/* 338 */         Boolean parentResult = parent.getResult();
/* 339 */         if ((parentResult == null) || ((parentResult == Boolean.TRUE) && (parent.getTerm().isAnd())) || ((parentResult == Boolean.FALSE) && (!parent.getTerm().isAnd())))
/*     */         {
/*     */ 
/* 342 */           parent.setResult(evaluate(term));
/*     */         }
/*     */         
/*     */ 
/*     */       }
/*     */       else
/*     */       {
/* 349 */         this.mParentResult.push(new Result(evaluate(term), null));
/*     */       }
/*     */     }
/*     */     
/*     */     private boolean evaluate(EntrySearchFilter.Single term) {
/* 354 */       String opAttr = term.getLhs();
/*     */       
/* 356 */       Object value = this.mContact.get(opAttr);
/* 357 */       if ((value instanceof String[])) {
/* 358 */         for (String v : (String[])value) {
/* 359 */           if (shouldInclude(term, v))
/* 360 */             return true;
/*     */         }
/* 362 */         return false; }
/* 363 */       if (value != null) {
/* 364 */         return shouldInclude(term, value.toString());
/*     */       }
/* 366 */       return false;
/*     */     }
/*     */     
/*     */     private boolean shouldInclude(EntrySearchFilter.Single term, String value)
/*     */     {
/* 371 */       EntrySearchFilter.Operator op = term.getOperator();
/* 372 */       String opVal = term.getRhs();
/* 373 */       boolean result = true;
/*     */       
/* 375 */       if (op.equals(EntrySearchFilter.Operator.has)) {
/* 376 */         result = value == null ? false : value.toLowerCase().contains(opVal.toLowerCase());
/* 377 */       } else if (op.equals(EntrySearchFilter.Operator.eq)) {
/* 378 */         result = value == null ? false : value.toLowerCase().equals(opVal.toLowerCase());
/* 379 */       } else if (op.equals(EntrySearchFilter.Operator.ge))
/*     */       {
/* 381 */         result = value != null;
/* 382 */       } else if (op.equals(EntrySearchFilter.Operator.le))
/*     */       {
/* 384 */         result = value != null;
/* 385 */       } else if (op.equals(EntrySearchFilter.Operator.startswith)) {
/* 386 */         result = value == null ? false : value.toLowerCase().startsWith(opVal.toLowerCase());
/* 387 */       } else if (op.equals(EntrySearchFilter.Operator.endswith)) {
/* 388 */         result = value == null ? false : value.toLowerCase().endsWith(opVal.toLowerCase());
/*     */       }
/*     */       else {
/* 391 */         result = value == null ? false : value.toLowerCase().equals(opVal.toLowerCase());
/*     */       }
/*     */       
/* 394 */       if (term.isNegation()) {
/* 395 */         return !result;
/*     */       }
/* 397 */       return result;
/*     */     }
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/gal/GalExtraSearchFilter.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */